use serde::{Deserialize, Serialize};
use sqlx::{
    types::chrono::{DateTime, NaiveDateTime, Utc},
    PgPool, Postgres, Transaction,
};

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct InitTodoItem {
    pub owner_key: String,
    pub title: String,
    pub description: Option<String>,
}
impl InitTodoItem {
    pub async fn exec(
        &self,
        tx: &mut Transaction<'_, Postgres>,
        id: &str,
    ) -> Result<(), sqlx::Error> {
        sqlx::query!(
            r#"  
            INSERT INTO todo_list (id, owner_key, title, description, finished)  
            VALUES ($1, $2, $3, $4, $5)  
            "#,
            id,
            &self.owner_key,
            &self.title,
            self.description.as_deref(),
            false,
        )
        .execute(&mut **tx)
        .await?;

        Ok(())
    }
}
#[derive(Debug, Clone, PartialEq, sqlx::FromRow)]
pub struct TodoItem {
    pub id: String,
    pub owner_key: String,
    pub title: String,
    pub description: Option<String>,
    pub finished: Option<bool>,
    pub created_at: Option<NaiveDateTime>,
    pub updated_at: Option<NaiveDateTime>,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct TodoUpdateItem {
    pub id: String,
    pub owner_key: String,
    pub title: String,
    pub description: Option<String>,
    pub finished: Option<bool>,
}
impl TodoUpdateItem {
    pub async fn exec(&self, tx: &mut Transaction<'_, Postgres>) -> Result<(), sqlx::Error> {
        sqlx::query!(
            r#"
            UPDATE todo_list 
            SET
                title = $1,
                description = COALESCE($2,description),
                finished = COALESCE($3, finished)
            WHERE
                id = $4 AND owner_key = $5
            "#,
            self.title,
            self.description,
            self.finished,
            self.id,
            self.owner_key
        )
        .execute(&mut **tx)
        .await?;

        Ok(())
    }
}
pub struct OwnerItem {
    pub owner_key: String,
}
impl OwnerItem {
    pub async fn exec(&self, pool: &PgPool) -> Result<Vec<TodoItem>, sqlx::Error> {
        // 编写SQL查询，以owner_key为条件
        let items = sqlx::query_as!(
            TodoItem,
            "SELECT id, owner_key, title, description, finished, created_at, updated_at  
        FROM todo_list  
        WHERE owner_key = $1",
            &self.owner_key
        )
        .fetch_all(pool) // 执行查询并获取所有结果
        .await?;

        Ok(items)
    }
}
pub struct IdItem {
    pub id: String,
}
impl IdItem {
    pub async fn rm(&self, tx: &mut Transaction<'_, Postgres>) -> Result<(), sqlx::Error> {
        sqlx::query!(
            r#"
            Delete from todo_list 
            WHERE
                id = $1
            "#,
            self.id
        )
        .execute(&mut **tx)
        .await?;

        Ok(())
    }
    pub async fn get(&self, pool: &PgPool) -> Result<Option<TodoItem>, sqlx::Error> {
        let items = sqlx::query_as!(
            TodoItem,
            r#"  
        SELECT id, owner_key, title, description, finished, created_at, updated_at  
        FROM todo_list  
        WHERE id = $1  
        "#,
            &self.id
        )
        .fetch_all(pool) // 执行查询并获取所有结果
        .await?;

        Ok(items.first().cloned())
    }
}
